/*
 * 颜色字段显示驱动程序 - 为ColorField实现显示和编辑逻辑
 * 
 * 主要功能：
 * - 为ColorField实现显示形状生成
 * - 提供颜色字段的编辑界面
 * - 实现颜色值的验证逻辑
 * - 支持字段设置的集成
 */

using Lombiq.TrainingDemo.Fields;
using Lombiq.TrainingDemo.Settings;
using Lombiq.TrainingDemo.ViewModels;
using Microsoft.Extensions.Localization;
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Display.Models;
using OrchardCore.ContentManagement.Metadata.Models;
using OrchardCore.DisplayManagement.Views;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Lombiq.TrainingDemo.Drivers;

/// <summary>
/// 颜色字段显示驱动程序 - 为ColorField实现显示和编辑逻辑
/// 
/// 主要用途：
/// - 为ColorField实现显示形状生成
 /* - 提供颜色字段的编辑界面
 * - 实现颜色值的验证逻辑
 * - 支持字段设置的集成
 * 
 * 使用场景：
 * - 显示颜色字段的值和名称
 * - 编辑颜色字段的值
 * - 验证颜色值的格式
 * - 集成字段设置进行验证
 * 
 * 设计原因：
 * - 为自定义内容字段提供完整的显示和编辑支持
 * - 实现字段级别的验证逻辑
 * - 支持字段设置的动态配置
 * - 提供可重用的颜色字段组件
 * 
 * 设计模式：
 * - 驱动模式：继承ContentFieldDisplayDriver实现字段逻辑
 * - 视图模型模式：使用专门的ViewModel传递数据
 * - 验证模式：实现自定义验证逻辑
 * - 设置模式：集成字段设置进行配置
/// </summary>
// 您不应该感到惊讶 - 内容字段也有显示驱动程序。ContentFieldDisplayDriver专门用于内容字段。
// 不要忘记在服务提供程序中注册此类（请参阅：Startup.cs）。
 */
public partial class ColorFieldDisplayDriver : ContentFieldDisplayDriver<ColorField>
{
    private readonly IStringLocalizer T;

    /// <summary>
    /// 构造函数 - 注入本地化服务
    /// </summary>
    /// <param name="stringLocalizer">字符串本地化器</param>
    public ColorFieldDisplayDriver(IStringLocalizer<ColorFieldDisplayDriver> stringLocalizer) => T = stringLocalizer;

    /// <summary>
    /// 显示方法 - 为ColorField生成显示形状
    /// 
    /// 功能说明：
    /// - 使用Initialize形状帮助器生成显示形状
    /// - 使用DisplayColorFieldViewModel传递数据
    /// - 定义显示位置（Content和SummaryAdmin）
    /// - 支持显示类型和替代形状
    /// 
    /// 显示位置：
    /// - Content：在内容区域显示
    /// - SummaryAdmin：在管理摘要区域显示
    /// </summary>
    /// <param name="field">要显示的ColorField</param>
    /// <param name="fieldDisplayContext">字段显示上下文</param>
    /// <returns>显示结果</returns>
    public override IDisplayResult Display(ColorField field, BuildFieldDisplayContext fieldDisplayContext) =>
        // 相同的Display方法用于生成显示形状，但这次使用Initialize形状帮助器。
        // 我们在PersonPartDisplayDriver.Edit方法中见过它。为此，我们需要一个视图模型对象，
        // 该对象将用字段数据填充。GetDisplayShapeType帮助器将为我们的内容字段生成传统的形状类型，
        // 这将是字段的名称。显然，也可以使用替代形状 - 因此如果内容项以名为"Custom"的显示类型显示，
        // 则将使用ColorField.Custom.cshtml文件，否则将激活ColorField.cshtml。
        Initialize<DisplayColorFieldViewModel>(
            GetDisplayShapeType(fieldDisplayContext),
            viewModel =>
            {
                viewModel.Field = field;
                viewModel.Part = fieldDisplayContext.ContentPart;
                viewModel.PartFieldDefinition = fieldDisplayContext.PartFieldDefinition;
            })
        .Location("Content")
        .Location("SummaryAdmin", string.Empty);

    /// <summary>
    /// 编辑方法 - 为ColorField生成编辑形状
    /// 
    /// 功能说明：
    /// - 使用Initialize形状帮助器生成编辑形状
    /// - 使用EditColorFieldViewModel传递数据
    /// - 设置字段值和颜色名称
    /// - 传递相关上下文信息
    /// </summary>
    /// <param name="field">要编辑的ColorField</param>
    /// <param name="context">编辑上下文</param>
    /// <returns>编辑结果</returns>
    public override IDisplayResult Edit(ColorField field, BuildFieldEditorContext context) =>
        // 这里没有什么新内容，使用Initialize形状帮助器生成编辑形状。
        Initialize<EditColorFieldViewModel>(
            GetEditorShapeType(context),
            viewModel =>
            {
                viewModel.Value = field.Value;
                viewModel.ColorName = field.ColorName;
                viewModel.Field = field;
                viewModel.Part = context.ContentPart;
                viewModel.PartFieldDefinition = context.PartFieldDefinition;
            });

    /// <summary>
    /// 更新方法 - 处理ColorField的更新逻辑
    /// 
    /// 功能说明：
    /// - 更新字段值
    /// - 验证颜色值格式
    /// - 检查必填字段设置
    /// - 返回编辑结果
    /// 
    /// 验证逻辑：
    /// - 检查必填字段设置
    /// - 验证十六进制颜色格式
    /// - 添加相应的错误消息
    /// </summary>
    /// <param name="field">要更新的ColorField</param>
    /// <param name="context">更新上下文</param>
    /// <returns>更新结果</returns>
    public override async Task<IDisplayResult> UpdateAsync(ColorField field, UpdateFieldEditorContext context)
    {
        var updater = context.Updater;
        var viewModel = new EditColorFieldViewModel();

        // 使用模型更新器的此重载，您可以具体说明需要更新哪些属性。这样您可以确保没有其他属性会绑定到视图模型。
        // 除此之外，您可以在属性上放置[BindNever]属性，使模型绑定器跳过这些属性，这取决于您。
        await updater.TryUpdateModelAsync(viewModel, Prefix, viewModel => viewModel.Value, viewModel => viewModel.ColorName);

        // 获取ColorFieldSettings以在验证视图模型时使用它。
        var settings = context.PartFieldDefinition.GetSettings<ColorFieldSettings>();
        if (settings.Required && string.IsNullOrWhiteSpace(viewModel.Value))
        {
            updater.ModelState.AddModelError(Prefix, T["A value is required for {0}.", context.PartFieldDefinition.DisplayName()]);
        }

        // 还为我们的ColorField十六进制值进行一些自定义验证。
        var isInvalidHexColor = !string.IsNullOrWhiteSpace(viewModel.Value) &&
                                !RegexExpression().IsMatch(viewModel.Value);

        if (isInvalidHexColor) updater.ModelState.AddModelError(Prefix, T["The given color is invalid."]);

        field.ColorName = viewModel.ColorName;
        field.Value = viewModel.Value;

        return await EditAsync(field, context);
    }

    /// <summary>
    /// 正则表达式 - 验证十六进制颜色格式
    /// 
    /// 功能说明：
    /// - 匹配3位、6位或8位十六进制颜色值
    /// - 支持带#前缀的颜色值
    /// - 用于验证颜色字段的输入格式
    /// </summary>
    /// <returns>颜色格式验证正则表达式</returns>
    [GeneratedRegex("^#([A-Fa-f0-9]{8}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", RegexOptions.ExplicitCapture, matchTimeoutMilliseconds: 1000)]
    private static partial Regex RegexExpression();
}

// 训练部分结束：内容字段开发

// 下一站：Indexing/ColorFieldIndexHandler.cs
